#include "avro/basics.h"
#include "avro_napi.h"
#include <cstddef>
#include <cstdint>
#include <sys/param.h>

#define STR_DEFAULT_SIZE 2048

// 从二进制缓冲区中读取变长整数（variable-length integer），并进行解码（符合 Avro 等序列化协议中对整数 /
// 长整数的编码规范）; pos 为返回值，为实际数据的位置
long AvroTypeC::ReadLong(uint8_t *uData, long &pos) {
    if (uData == nullptr) {
        return OHOS_AVRO_LONG_ERR_LONG_NO;
    }
    long n = 0; // 用于存储解码过程中的整数（前28位用整数处理）
    long k = 0; // 记录当前已处理的位数（每次累加7，因为每个字节贡献7位有效数据）
    uint8_t *buf = uData; // 实例关联的二进制缓冲区
    long b = 0;           // b=当前字节
    long h = 0;           // f=浮点数（处理长整数）
    long f = 0;           // h=延续标志，
    long fk = 0;          // fk=浮点数计算的权重

    pos = 0;

    do {
        b = buf[pos++]; // 读取当前位置的字节，并将指针后移一位
        h = b & 0x80;   // 提取最高位（0x80 = 10000000b），判断是否还有后续字节（h≠0则继续）
        n |= (b & 0x7f) << k; // 提取低7位有效数据（b&0x7f），左移k位后合并到n中
        k += 7;               // 累加已处理的位数（每次7位）
    } while (h && k < 28);    // 循环条件：有后续字节（h≠0）且未超过28位（4×7）

    if (h) { // 如果h≠0，说明还有更多字节（超过28位）
        // 切换到浮点数运算，避免整数溢出
        f = n;          // 用浮点数f承接之前的28位数据
        fk = 268435456; // 2^28（后续字节的权重起点）
        do {
            b = buf[pos++];       // 继续读取下一个字节
            f += (b & 0x7f) * fk; // 低7位数据 × 当前权重，累加到f中
            fk *= 128;            // 权重×128（即×2^7，因为每个字节贡献7位）
        } while (b & 0x80);       // 直到某字节最高位为0（无后续字节）

        // ZigZag解码：将无符号浮点数转换为有符号整数
        return (f % 2 ? -(f + 1) : f) / 2;
    }

    return (n >> 1) ^ -(n & 1);
}

int AvroTypeC::MatchLong(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2) {
    long pos1 = 0;
    long n1 = ReadLong((uint8_t *)buffer_data, pos1);
    long pos2 = 0;
    long n2 = ReadLong((uint8_t *)buffer_data2, pos2);
    if (n1 == OHOS_AVRO_LONG_ERR_LONG_NO || n2 == OHOS_AVRO_LONG_ERR_LONG_NO) {
        return OHOS_AVRO_LONG_ERR_LONG_NO;
    }
    return n1 == n2 ? 0 : (n1 < n2 ? -1 : 1);
}

/**
 * 从二进制缓冲区以小端序读取 32 位单精度浮点数
 * @param buf 二进制缓冲区（unsigned char 数组）
 * @param buf_size 缓冲区总大小（字节数）
 * @param pos 读取的起始位置（字节索引）
 * @return 解析后的 32 位单精度浮点数
 */
float AvroTypeC::ReadFloatLE(const unsigned char *buf, size_t buf_size, size_t pos) {
    // 边界检查：确保 pos + 3 不超过缓冲区大小（需要 4 字节）
    if (pos + 3 >= buf_size) {
        LOGERROR("Buffer overflow: insufficient bytes for float");
        return OHOS_AVRO_ERR_NO;
    }

    // 从缓冲区读取 4 个字节，按小端序拼接为 32 位无符号整数
    // 小端序：低地址字节对应整数的低 8 位，高地址字节对应高 8 位
    uint32_t bytes = (static_cast<uint32_t>(buf[pos])) |           // 第 0 字节（最低位）
                     (static_cast<uint32_t>(buf[pos + 1]) << 8) |  // 第 1 字节
                     (static_cast<uint32_t>(buf[pos + 2]) << 16) | // 第 2 字节
                     (static_cast<uint32_t>(buf[pos + 3]) << 24);  // 第 3 字节（最高位）

    // 将 32 位整数的内存表示直接映射为 float（利用 IEEE 754 格式一致性）
    return *reinterpret_cast<float *>(&bytes);
}

float AvroTypeC::ReadFloat(uint8_t *buf, int len) {
    int pos = 0;
    pos += 4;
    if (pos > len) {
        return OHOS_AVRO_ERR_NO;
    }
    return ReadFloatLE(buf, len, 0);
}

int AvroTypeC::MatchFloat(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2) {
    float n1 = ReadFloat((uint8_t *)buffer_data, buffer_len);
    float n2 = ReadFloat((uint8_t *)buffer_data2, buffer_len2);
    if (n1 == OHOS_AVRO_ERR_NO || n2 == OHOS_AVRO_ERR_NO) {
        return OHOS_AVRO_ERR_NO;
    }
    // 浮点数==比较会有问题
    return n1 == n2 ? 0 : (n1 < n2 ? -1 : 1);
}

/**
 * 从二进制缓冲区以小端序读取 64 位双精度浮点数
 * @param buf 二进制缓冲区（unsigned char 数组）
 * @param buf_size 缓冲区总大小（字节数）
 * @param pos 读取的起始位置（字节索引）
 * @return 解析后的 64 位双精度浮点数
 */
double AvroTypeC::ReadDoubleLE(const unsigned char *buf, size_t buf_size, size_t pos) {
    // 边界检查：确保 pos + 7 不超过缓冲区大小（需要 8 字节）
    if (pos + 7 >= buf_size) {
        LOGERROR("Buffer overflow: insufficient bytes for double");
        return OHOS_AVRO_ERR_NO;
    }

    // 从缓冲区读取 8 个字节，按小端序拼接为 64 位无符号整数
    // 小端序：低地址字节对应整数的低 8 位，高地址字节对应高 8 位
    uint64_t bytes = (static_cast<uint64_t>(buf[pos])) |           // 第 0 字节（最低位）
                     (static_cast<uint64_t>(buf[pos + 1]) << 8) |  // 第 1 字节
                     (static_cast<uint64_t>(buf[pos + 2]) << 16) | // 第 2 字节
                     (static_cast<uint64_t>(buf[pos + 3]) << 24) | // 第 3 字节
                     (static_cast<uint64_t>(buf[pos + 4]) << 32) | // 第 4 字节
                     (static_cast<uint64_t>(buf[pos + 5]) << 40) | // 第 5 字节
                     (static_cast<uint64_t>(buf[pos + 6]) << 48) | // 第 6 字节
                     (static_cast<uint64_t>(buf[pos + 7]) << 56);  // 第 7 字节（最高位）

    // 将 64 位整数的内存表示直接映射为 double（利用 IEEE 754 格式一致性）
    return *reinterpret_cast<double *>(&bytes);
}


double AvroTypeC::ReadDouble(uint8_t *buf, int len) {
    int pos = 0;
    pos += 8;
    if (pos > len) {
        return OHOS_AVRO_ERR_NO;
    }
    return ReadDoubleLE(buf, len, 0);
}

int AvroTypeC::MatchDouble(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2) {
    double n1 = ReadDouble((uint8_t *)buffer_data, buffer_len);
    double n2 = ReadDouble((uint8_t *)buffer_data2, buffer_len2);
    if (n1 == OHOS_AVRO_ERR_NO || n2 == OHOS_AVRO_ERR_NO) {
        return OHOS_AVRO_ERR_NO;
    }
    // 浮点数==比较会有问题
    return n1 == n2 ? 0 : (n1 < n2 ? -1 : 1);
}

int AvroTypeC::MatchString(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2) {
    // 获取长度
    long pos1 = 0; // 实际数据的位置
    long n1 = ReadLong((uint8_t *)buffer_data, pos1);
    long pos2 = 0; // 实际数据的位置
    long n2 = ReadLong((uint8_t *)buffer_data2, pos2);

    if (pos1 > buffer_len || pos2 > buffer_len2) {
        return OHOS_AVRO_ERR_NO;
    }

    int len = MIN(n1, n2);
    for (int i = 0; i < len; i++) {
        // 定位到实际的数据比较
        long res = ((uint8_t *)buffer_data)[i + pos1] - ((uint8_t *)buffer_data2)[i + pos2];
        if (res == 0) {
            continue;
        }
        return res;
    }

    return n1 - n2;
}

int AvroTypeC::MatchBytes(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2) {
    // 获取长度
    long pos1 = 0; // 实际数据的位置
    long n1 = ReadLong((uint8_t *)buffer_data, pos1);
    long pos2 = 0; // 实际数据的位置
    long n2 = ReadLong((uint8_t *)buffer_data2, pos2);

    if (pos1 > buffer_len || pos2 > buffer_len2) {
        return OHOS_AVRO_ERR_NO;
    }

    int len = MIN(n1, n2);
    for (int i = 0; i < len; i++) {
        // 定位到实际的数据比较
        long res = buffer_data[i + pos1] - buffer_data2[i + pos2];
        if (res == 0) {
            continue;
        }
        return res;
    }

    return n1 - n2;
}

int AvroTypeC::MatchFixed(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2) {
    if (buffer_len != buffer_len2) {
        return OHOS_AVRO_ERR_NO;
    }

    for (int i = 0; i < buffer_len; i++) {
        int res = ((uint8_t *)buffer_data)[i] - ((uint8_t *)buffer_data2)[i];
        if (res == 0) {
            continue;
        }
        return res;
    }

    return 0;
}

int AvroTypeC::Compare_Buffers(const uint8_t *buffer_data, int buffer_len, const uint8_t *buffer_data2, int buffer_len2,
                               avro_schema_t schema) {
    switch (schema->type) {
    case AVRO_INT32:
    case AVRO_INT64:
    case AVRO_ENUM:
        return MatchLong(buffer_data, buffer_len, buffer_data2, buffer_len2);
    case AVRO_FLOAT:
        return MatchFloat(buffer_data, buffer_len, buffer_data2, buffer_len2);
    case AVRO_DOUBLE:
        return MatchDouble(buffer_data, buffer_len, buffer_data2, buffer_len2);
    case AVRO_BOOLEAN:
        return ((uint8_t *)buffer_data)[0] - ((uint8_t *)buffer_data2)[0];
    case AVRO_NULL:
        return 0;
    case AVRO_STRING:
        return MatchString(buffer_data, buffer_len, buffer_data2, buffer_len2);
    case AVRO_BYTES:
        return MatchBytes(buffer_data, buffer_len, buffer_data2, buffer_len2);
    case AVRO_FIXED:
        return MatchFixed(buffer_data, buffer_len, buffer_data2, buffer_len2);
    case AVRO_ARRAY:
    case AVRO_MAP:
    case AVRO_RECORD:
    case AVRO_UNION:
        return OHOS_AVRO_ERR_NO; // 目前不支持
    default:
        return OHOS_AVRO_ERR_NO;
    }

    return OHOS_AVRO_ERR_NO;
}

napi_value AvroTypeC::CompareBuffers(napi_env env, napi_callback_info info) {
    napi_value result;
    size_t argc = 2;
    napi_value args[2];
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
    if (status != napi_ok || argc < 1) {
        LOGERROR("Get cb failed！");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Failed to napi_unwrap");
        return nullptr;
    }

    int res = OHOS_AVRO_ERR_NO;
    void *buffer_data;
    size_t buffer_len = 0;
    status = napi_get_arraybuffer_info(env, args[0], &buffer_data, &buffer_len);
    if (status != napi_ok) {
        LOGERROR("Get buffer info failed！");
        return nullptr;
    }

    void *buffer_data2;
    size_t buffer_len2 = 0;
    status = napi_get_arraybuffer_info(env, args[1], &buffer_data2, &buffer_len2);
    if (status != napi_ok) {
        LOGERROR("Get buffer info failed！");
        return nullptr;
    }
    res = Compare_Buffers((const uint8_t *)buffer_data, buffer_len, (const uint8_t *)buffer_data2, buffer_len2,
                          obj->schema_);
    if (res == OHOS_AVRO_ERR_NO || res == OHOS_AVRO_LONG_ERR_LONG_NO) {
        LOGERROR("Failed to compare buffer!");
        return nullptr;
    }

    status = napi_create_int32(env, res, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create int32!");
        return nullptr;
    }

    return result;
}

int AvroTypeC::Compare_int32(napi_env env, napi_value val1, napi_value val2) {
    if (!ValidateNumber(env, val1) || !ValidateNumber(env, val2)) {
        LOGERROR("Data error!");
        return OHOS_AVRO_ERR_NO;
    }
    LOGERROR("Data OK!");
    int32_t value1;
    napi_status status = napi_get_value_int32(env, val1, &value1);
    STATUS_CHECK(status);

    int32_t value2;
    status = napi_get_value_int32(env, val2, &value2);
    STATUS_CHECK(status);

    return avro_compare(value1, value2);
}

int AvroTypeC::Compare_int64(napi_env env, napi_value val1, napi_value val2) {
    if (!ValidateNumber(env, val1) || !ValidateNumber(env, val2)) {
        return OHOS_AVRO_ERR_NO;
    }
    int64_t value1;
    napi_status status = napi_get_value_int64(env, val1, &value1);
    STATUS_CHECK(status);

    int64_t value2;
    status = napi_get_value_int64(env, val2, &value2);
    STATUS_CHECK(status);

    return avro_compare(value1, value2);
}

int AvroTypeC::Compare_double(napi_env env, napi_value val1, napi_value val2, bool isfloat) {
    if (!ValidateNumber(env, val1) || !ValidateNumber(env, val2)) {
        return OHOS_AVRO_ERR_NO;
    }
    double value1;
    napi_status status = napi_get_value_double(env, val1, &value1);
    STATUS_CHECK(status);

    double value2;
    status = napi_get_value_double(env, val2, &value2);
    STATUS_CHECK(status);

    // 处理Infinity：正无穷>一切，负无穷<一切
    if (isinf(value1) && isinf(value2)) {
        return (value1 == value2) ? 0 : (value1 > value2 ? 1 : -1);
    }
    if (isinf(value1)) {
        return value1 > 0 ? 1 : -1;
    }
    if (isinf(value2)) {
        return value2 > 0 ? -1 : 1;
    }

    // 常规值：先判断是否近似相等
    if ((isfloat && (fabs(value1 - value2) < FLOAT_EPSILON)) ||
        (!isfloat && (fabs(value1 - value2) < DOUBLE_EPSILON))) {
        return 0;
    }
    // 不相等时判断大小
    return value1 < value2 ? -1 : 1;
}

int AvroTypeC::Compare_string(napi_env env, napi_value val1, napi_value val2) {
    if (!ValidateString(env, val1) || !ValidateString(env, val2)) {
        return OHOS_AVRO_ERR_NO;
    }
    std::string str1;
    NapiUtil::JsValueToString(env, val1, STR_DEFAULT_SIZE, str1);
    if (str1.empty()) {
        return OHOS_AVRO_ERR_NO;
    }

    std::string str2;
    NapiUtil::JsValueToString(env, val2, STR_DEFAULT_SIZE, str2);
    if (str1.empty()) {
        return OHOS_AVRO_ERR_NO;
    }

    size_t a_len = str1.length();
    size_t b_len = str2.length();
    size_t min_len = (a_len < b_len) ? a_len : b_len;
    int cmp = strncmp(str1.c_str(), str2.c_str(), min_len);
    if (cmp != 0) {
        return (cmp < 0) ? -1 : 1;
    }
    // 前缀相同，短字符串更小
    return a_len - b_len;
}

int AvroTypeC::Compare_bool(napi_env env, napi_value val1, napi_value val2) {
    if (!ValidateBoolean(env, val1) || !ValidateBoolean(env, val2)) {
        return OHOS_AVRO_ERR_NO;
    }
    bool value0;
    napi_status status = napi_get_value_bool(env, val1, &value0);
    STATUS_CHECK(status);

    bool value1;
    status = napi_get_value_bool(env, val2, &value1);
    STATUS_CHECK(status);

    return value0 - value1;
}

int AvroTypeC::Compare_enum(napi_env env, napi_value val1, napi_value val2, avro_schema_t schema) {
    if (!ValidateEnum(env, val1, schema) || !ValidateEnum(env, val2, schema)) {
        return OHOS_AVRO_ERR_NO;
    }
    std::string str1;
    NapiUtil::JsValueToString(env, val1, STR_DEFAULT_SIZE, str1);
    if (str1.empty()) {
        return OHOS_AVRO_ERR_NO;
    }
    int enum_index1 = avro_schema_enum_get_by_name(schema, str1.c_str());

    std::string str2;
    NapiUtil::JsValueToString(env, val2, STR_DEFAULT_SIZE, str2);
    if (str1.empty()) {
        return OHOS_AVRO_ERR_NO;
    }
    int enum_index2 = avro_schema_enum_get_by_name(schema, str2.c_str());

    return enum_index1 - enum_index2;
}

int AvroTypeC::Compare_fixed(napi_env env, napi_value val1, napi_value val2, avro_schema_t schema) {
    if (!ValidateFixed(env, val1, schema) || !ValidateFixed(env, val2, schema)) {
        return OHOS_AVRO_ERR_NO;
    }

    napi_status status;
    uint32_t length = 0;
    status = napi_get_array_length(env, val1, &length);
    for (int i = 0; i < length; i++) {
        napi_value key;
        status = napi_get_element(env, val1, i, &key);
        STATUS_CHECK(status);

        uint32_t num_value;
        status = napi_get_value_uint32(env, key, &num_value);
        STATUS_CHECK(status);

        napi_value key2;
        status = napi_get_element(env, val2, i, &key2);
        STATUS_CHECK(status);

        uint32_t num_value2;
        status = napi_get_value_uint32(env, key2, &num_value2);
        STATUS_CHECK(status);

        if (num_value == num_value2) {
            continue;
        }

        return num_value - num_value2;
    }

    return 0;
}

int AvroTypeC::Compare_bytes(napi_env env, napi_value val1, napi_value val2) {
    if (!ValidateBytes(env, val1) || !ValidateBytes(env, val2)) {
        return OHOS_AVRO_ERR_NO;
    }

    napi_status status;
    uint32_t length = 0;
    status = napi_get_array_length(env, val1, &length);
    uint32_t length2 = 0;
    status = napi_get_array_length(env, val2, &length2);

    uint32_t minLen = length < length2 ? length : length2;
    for (int i = 0; i < minLen; i++) {
        napi_value key;
        status = napi_get_element(env, val1, i, &key);
        STATUS_CHECK(status);

        uint32_t num_value;
        status = napi_get_value_uint32(env, key, &num_value);
        STATUS_CHECK(status);

        napi_value key2;
        status = napi_get_element(env, val2, i, &key2);
        STATUS_CHECK(status);

        uint32_t num_value2;
        status = napi_get_value_uint32(env, key2, &num_value2);
        STATUS_CHECK(status);

        if (num_value == num_value2) {
            continue;
        }

        return num_value - num_value2;
    }

    return length - length2;
}

int AvroTypeC::Compare_full(napi_env env, napi_value val1, napi_value val2, avro_schema_t schema) {
    switch (schema->type) {
    case AVRO_INT32:
        return Compare_int32(env, val1, val2);
    case AVRO_INT64:
        return Compare_int64(env, val1, val2);
    case AVRO_ENUM:
        return Compare_enum(env, val1, val2, schema);
    case AVRO_FLOAT:
        return Compare_double(env, val1, val2, true);
    case AVRO_DOUBLE:
        return Compare_double(env, val1, val2, false);
    case AVRO_BOOLEAN:
        return Compare_bool(env, val1, val2);
    case AVRO_NULL:
        return 0;
    case AVRO_STRING:
        return Compare_string(env, val1, val2);
    case AVRO_BYTES:
        return Compare_bytes(env, val1, val2);
    case AVRO_FIXED:
        return Compare_fixed(env, val1, val2, schema);
    case AVRO_ARRAY:
    case AVRO_MAP:
    case AVRO_RECORD:
    case AVRO_UNION:
        return OHOS_AVRO_ERR_NO; // 目前不支持
    default:
        return OHOS_AVRO_ERR_NO;
    }

    return OHOS_AVRO_ERR_NO;
}

napi_value AvroTypeC::Compare(napi_env env, napi_callback_info info) {
    napi_value result;
    size_t argc = 2;
    napi_value args[2];
    napi_value jsthis;
    napi_status status = napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
    if (status != napi_ok || argc < 1) {
        LOGERROR("Get cb failed！");
        return nullptr;
    }

    AvroTypeC *obj;
    status = napi_unwrap(env, jsthis, (void **)&obj);
    if (status != napi_ok) {
        LOGERROR("Failed to napi_unwrap");
        return nullptr;
    }

    int res = Compare_full(env, args[0], args[1], obj->schema_);
    if (res == OHOS_AVRO_ERR_NO) {
        LOGERROR("Failed to compare!");
        return nullptr;
    }
    status = napi_create_int32(env, res, &result);
    if (status != napi_ok) {
        LOGERROR("Failed to create int32!");
        return nullptr;
    }

    return result;
}